package com.zatech.cgnci.project.base.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;

/**
 * 日期常用格式
 */
public class DateUtils {

    /**
     * yyyyMMddHHmmss
     **/
    public static final String COMPACT_DATE_TIME_PATTERN = "yyyyMMddHHmmss";

    /**
     * yyyy-MM-dd HH:mm:ss
     **/
    public static final String FORMAT_2 = "yyyy-MM-dd HH:mm:ss";

    /**
     * yyyy-MM-dd
     **/
    public static final String FORMAT_3 = "yyyy-MM-dd";

    /**
     * HH:mm:ss
     **/
    public static final String FORMAT_4 = "HH:mm:ss";

    public static final String FORMAT_5 = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";

    public static final String FORMAT_6 = "yyyy-MM-dd'T'HH:mm:ss'Z'";

    public static final String FORMAT_7 = "yyyy-MM-dd HH:mm:ss.SSS";
    /**
     * yyyy/MM/dd
     **/
    public static final String FORMAT_8 = "yyyy/MM/dd";

    public static final SimpleDateFormat SDF = new SimpleDateFormat(DateUtils.FORMAT_3);

    public static String dateToString(Date date, String format) {
        return DateFormatUtils.format(date, format);
    }

    public static String compactDateTime(Date date) {
        return DateFormatUtils.format(date, COMPACT_DATE_TIME_PATTERN);
    }


    public static String getDate(String format) {
        return DateFormatUtils.format(new Date(), format);
    }


    public static String timeToDate(String time, String formatTime, String formatDate) throws ParseException {
        try {
            SimpleDateFormat formatIn = new SimpleDateFormat(formatTime); // 输入日期时间字符串的格式
            Date date = formatIn.parse(time); // 解析输入字符串得到Date对象
            SimpleDateFormat formatOut = new SimpleDateFormat(formatDate); // 输出日期时间字符串的格式
            return formatOut.format(date); // 格式化Date对象为指定格式的字符串
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    public static String calendarToString(Calendar calendar, String format) {
        return DateFormatUtils.format(calendar, format);
    }

    public static String longToString(Long millis, String format) {
        return DateFormatUtils.format(millis, format);
    }

    public static Date longToDate(Long millis) {
        String dateStr = longToString(millis, FORMAT_2);
        try {
            return org.apache.commons.lang3.time.DateUtils.parseDate(dateStr, FORMAT_2);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    public static Date strToDate(String strDate, String format) {
        SimpleDateFormat formatter = new SimpleDateFormat(format);
        ParsePosition pos = new ParsePosition(0);
        return formatter.parse(strDate, pos);
    }

    /**
     * 获取前几天
     *
     * @param date 当前时间
     * @param day  天数
     * @return
     */
    public static Date getBeforeDateByDay(Date date, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) - day);
        return calendar.getTime();
    }


    /**
     * 获取前几分钟
     *
     * @param date 当前时间
     * @param min  天数
     * @return
     */
    public static Date getBeforeDateByMinit(Date date, int min) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.SECOND, calendar.get(Calendar.SECOND) - min * 60);
        return calendar.getTime();
    }

    public static Date getAfterDateByMinit(Date date, int min) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.SECOND, calendar.get(Calendar.SECOND) + min * 60);
        return calendar.getTime();
    }

    /**
     * 获取后几天
     *
     * @param date 当前时间
     * @param day  天数
     * @return
     */
    public static Date getAfterDateByDay(Date date, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) + day);
        return calendar.getTime();
    }

    /**
     * 判断时间是否超出对应天数
     *
     * @param date 时间
     * @param day  天数
     * @return true没有超出 false超出
     */
    public static boolean checkDay(Date date, int day) {
        return LocalDateTime.now().isBefore(getAfterDateByDay(date, day).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
    }

    /**
     * 判断时间是否超出对应天数
     *
     * @param date 时间
     * @param day  天数
     * @return true没有超出 false超出
     */
    public static boolean checkDay(String date, int day) {
        return LocalDateTime.now().isBefore(getAfterDateByDay(strToDate(date, FORMAT_2), day).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
    }

    /**
     * 添加 时分秒
     *
     * @param time 日期
     * @param type [start、end]=[00:00:00、23:59:59]
     */
//    public static String time(String time, String type) {
//        if (StringUtils.isBlank(time))
//            return time;
//        if ("start".equalsIgnoreCase(type)) {
//            return SDF.format(SDF.parse(time, new ParsePosition(0))) + " 00:00:00";
//        } else {
//            return SDF.format(SDF.parse(time, new ParsePosition(0))) + " 23:59:59";
//        }
//    }

    public static Date getTimeByType(Date date, String type) {
        if (VerifyUtils.isEmpty(date))
            return date;
        // 使用Calendar来修改时间部分
        Calendar calendar = Calendar.getInstance();
        // 设置Calendar的时间为Date对象的时间
        calendar.setTime(date);
        if ("start".equalsIgnoreCase(type)) {
            // 将时间部分设置为午夜（0点0分0秒）
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            // 还可以清除毫秒部分
            calendar.set(Calendar.MILLISECOND, 0);
        } else {
            // 将时间部分设置为23:59:59
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            // 如果需要更精确，可以设置为999毫秒
            calendar.set(Calendar.MILLISECOND, 999);
        }
        return calendar.getTime();
    }

    /**
     * 开始日期添加时分秒 （安全监测不过，暂时屏蔽，无地方用到）
     *
     * @param startTime
     * @param endTime
     */
//    public static void formatTime(String startTime, String endTime) {
//        if (StringUtils.isBlank(startTime) && StringUtils.isNotBlank(endTime)) {
//            startTime = SDF.format(SDF.parse(endTime, new ParsePosition(0))) + " 00:00:00";
//            endTime = SDF.format(SDF.parse(endTime, new ParsePosition(0))) + " 23:59:59";
//        } else if (StringUtils.isBlank(endTime) && StringUtils.isNotBlank(startTime)) {
//            startTime = SDF.format(SDF.parse(startTime, new ParsePosition(0))) + " 00:00:00";
//            endTime = SDF.format(SDF.parse(startTime, new ParsePosition(0))) + " 23:59:59";
//        } else {
//            startTime = StringUtils.isBlank(startTime) ? startTime : SDF.format(SDF.parse(startTime, new ParsePosition(0))) + " 00:00:00";
//            endTime = StringUtils.isBlank(endTime) ? endTime : SDF.format(SDF.parse(endTime, new ParsePosition(0))) + " 23:59:59";
//        }
//    }

    /**
     * 字符串转date
     *
     * @param source 时间
     * @param format 时间格式
     * @return
     */
    public static Date parseDate(String source, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            return sdf.parse(source);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * date转字符串
     *
     * @param source 时间
     * @param format 时间格式
     * @return
     */
    public static String formatDate(Date source, String format) {
        if(VerifyUtils.isEmpty(source)){
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            return sdf.format(source);
        } catch (Exception e) {
            return null;
        }
    }

    public static String dateElaborate() {
        // 获取当前日期和时间
        LocalDateTime now = LocalDateTime.now();
        // 定义时间格式：年月日时分秒毫秒
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        // 格式化当前时间为流水号
        return now.format(formatter);
    }

    /**
     * Date 转 LocalDateTime
     *
     * @param date
     * @return LocalDateTime
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        if (date == null) {
            return null;
        }
        long nanoOfSecond = (date.getTime() % 1000) * 1000000;
        return LocalDateTime.ofEpochSecond(date.getTime() / 1000, (int) nanoOfSecond, ZoneOffset.of("+8"));
    }

    /**
     * Date 转 LocalDate
     *
     * @param date
     * @return LocalDate
     */
    public static LocalDate dateToLocalDate(Date date) {
        if (date == null) {
            return null;
        }
        return dateToLocalDateTime(date).toLocalDate();
    }

    /**
     * 计算两个日期相差的天数,相同日期为0天
     *
     * @param before 前一日期
     * @param after  后一日期
     * @return int 天数
     */
    public static Integer getDiffDay(Date before, Date after) {
        if (before == null || after == null) {
            return null;
        }
        Long days = dateToLocalDate(before).until(dateToLocalDate(after), ChronoUnit.DAYS);
        return days.intValue();
    }



    /**
     * 将世界标准时间设置成为 北京时间
     *
     * @param date Date对象
     * @return 遵循rfc3339标准格式，格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE，YYYY-MM-DD表示年月日，T出现在字符串中，表示time元素的开头，HH:mm:ss.sss表示时分秒毫秒，TIMEZONE表示时区（+08:00表示东八区时间，领先UTC 8小时，即北京时间）。例如：2015-05-20T13:29:35.120+08:00表示，北京时间2015年5月20日 13点29分35秒。
     */
    public static String DateToCST(Date date) {
        if (Objects.isNull(date)) {
            return null;
        }
        return formatDate(date, FORMAT_5);
    }


    /**
     * 将世界标准时间设置成为 北京时间
     *
     * @param UTCDate 传入的世界标准时间字符串 格式为：  "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"  或者 "yyyy-MM-dd'T'HH:mm:ss'Z'" 其他格式返回原样字符串
     * @return 返回北京时间字符串 （过个在传入数据格式正确的情况下 返回 "yyyy-MM-dd HH:mm:ss" 格式)
     * @throws ParseException
     */
    public static String UTCToCST(String UTCDate) throws ParseException {
        String format;
        if (StringUtils.isBlank(UTCDate)) {
            return null;
        } else if (UTCDate.contains("T") && UTCDate.contains("Z") && UTCDate.contains(".")) {
            format = FORMAT_5;
        } else if (UTCDate.contains("T") && UTCDate.contains("Z")) {
            format = FORMAT_6;
        } else {
            return UTCDate;
        }
        SimpleDateFormat format1 = new SimpleDateFormat(format);
        Date date = format1.parse(UTCDate);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR, calendar.get(Calendar.HOUR) + 8);
        Date time = calendar.getTime();
        SimpleDateFormat format2 = new SimpleDateFormat(FORMAT_2);
        return format2.format(time);
    }

    /**
     * 获取精确到秒的时间戳
     *
     * @return
     */
    public static int getSecondTimestamp(Date date) {
        if (null == date) {
            return 0;
        }
        String timestamp = String.valueOf(date.getTime());
        int length = timestamp.length();
        if (length > 3) {
            return Integer.parseInt(timestamp.substring(0, length - 3));
        } else {
            return 0;
        }
    }

    /**
     * 获取时间戳
     *
     * @return
     */
    public static String getTimeStamp() {
        int time = (int) (System.currentTimeMillis() / 1000);
        return String.valueOf(time);
    }

    /**
     * rfc3339标准格式转日期
     *
     * @param dateStr  2024-01-20T13:29:35+08:00
     * @return
     */

    /**
     * 当前日期转rfc3339标准格式
     *
     * @return
     */
    public static String getRFC3339ByNow() {
        return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX")
                .format(new Date());
    }

    public static boolean areDatesEqual(Date date1, Date date2) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);

        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);

        return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
                cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH) &&
                cal1.get(Calendar.DAY_OF_MONTH) == cal2.get(Calendar.DAY_OF_MONTH);
    }


    public static String getEndMonth(String month) {
        // 定义日期格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/M");

        try {
            // 解析输入字符串为YearMonth对象
            YearMonth yearMonth = YearMonth.parse(month, formatter);
            // 获取该月的最后一天
            int lastDayOfMonth = yearMonth.atEndOfMonth().getDayOfMonth();
            // 输出结果
            return month + "/" + lastDayOfMonth;
        } catch (DateTimeParseException e) {
            return null;
        }
    }

    /**
     * 判断目标日期是否在起保日期和终保日期之间（包含起保日期和终保日期）
     *
     * @param targetDate 目标日期（期初日期）
     * @param startDate  起保日期
     * @param endDate    终保日期
     * @return 如果目标日期在范围内，返回true；否则返回false
     */
    public static boolean isDateInRange(Date targetDate, Date startDate, Date endDate) {
        LocalDate targetLocalDate = dateToLocalDate(targetDate);
        LocalDate startLocalDate = dateToLocalDate(startDate);
        LocalDate endLocalDate = dateToLocalDate(endDate);
        // 判断目标日期是否在起保日期和终保日期之间
        return !targetLocalDate.isBefore(startLocalDate) && !targetLocalDate.isAfter(endLocalDate);
    }

    /**
     * 判断入账日期是否早于期初日期
     *
     * @param entryDate 入账日期
     * @param startDate 期初日期
     * @return 如果入账日期早于期初日期，返回true；否则返回false
     */
    public static boolean isEntryDateBeforeStartDate(Date entryDate, Date startDate) {
        LocalDate entryLocalDate = dateToLocalDate(entryDate);
        LocalDate startLocalDate = dateToLocalDate(startDate);
        return entryLocalDate.isBefore(startLocalDate);
    }

    public static boolean lessThanEqualTo(Date entryDate, Date startDate) {
        LocalDate entryLocalDate = dateToLocalDate(entryDate);
        LocalDate startLocalDate = dateToLocalDate(startDate);
        return entryLocalDate.isBefore(startLocalDate) || entryLocalDate.isEqual(startLocalDate);
    }
}
